package com.gary.thread;

/**
 *
 * 1、创建资源类
 * 2、资源类中：判断、干活、通知
 * 3、线程调用
 * 也就是当前的线程不是此对象监视器的所有者。当前线程要锁定该对象之后，才能用锁定的对象执行这些方法，这里需要用到synchronized关键字，
 * 锁定哪个对象就用哪个对象来执行notify(), notifyAll(),wait(), wait(long), wait(long, int)操作，否则就会报IllegalMonitorStateException异常。
 *
 * @author peng_rui
 * @date 2022/3/14
 */

class Share {
    //资源
    public int num = 0;

    /**
     * +
     */
    public synchronized void incr() {
        //判断 为了避免虚假唤醒的问题，需要用while 循环包裹wait
        if (num != 0) {
            try {
                wait();//wait 方法 在那里睡，就在哪里醒， wait应该放在while循环中
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //干活
        num++;
        System.out.println(Thread.currentThread().getName() + " :: " + num);
        //通知
        notifyAll();
    }

    /**
     * -
     */
    public synchronized void decr() {
        //判断
        if (num != 1) {
            try {
                wait(); //wait 方法 在那里睡，就在哪里醒， wait应该放在while循环中
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //干活
        num--;
        System.out.println(Thread.currentThread().getName() + " :: " + num);
        //通知
        notifyAll();
    }
}
public class AddSubDemo {
    public static void main(String[] args) {
        Share share = new Share();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                share.incr();
            }
        }, "ADD").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                share.decr();
            }
        }, "SUB").start();
    }
}
